package com.teradata.olingo.controller;

import com.alibaba.fastjson.JSON;
import com.teradata.olingo.entity.CcdcODataServerError;
import com.teradata.olingo.listener.ODataAsynListener;
import com.teradata.olingo.processor.AsyncRequestProcessor;
import com.teradata.olingo.processor.ExceptionHandlingAsyncTaskExecutor;
import com.teradata.olingo.service.TestService;
import com.teradata.olingo.task.Task;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.AsyncContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.channels.Channel;
import java.util.concurrent.*;

/**
 * @Project: cmcchq
 * @Description:
 * @Version 1.0
 * @Throws :
 * @Author: <li>2019/5/6 lyndon Create 1.0
 * @Copyright (c)2019-2019 版权所有
 * @Modified By:
 */

@RestController
@RequestMapping("/ccc")
@Slf4j
public class EdmAsynController {

    @Autowired
    private Task task;

    @Autowired
    private TestService service;

    @RequestMapping("/test")
    @ResponseBody
    public Callable<String> callable() {
        System.out.println("test thread name:" + Thread.currentThread().getName());
        // 这么做的好处避免web server的连接池被长期占用而引起性能问题，
        // 调用后生成一个非web的服务线程来处理，增加web服务器的吞吐量。
        return new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println("call thread name:" + Thread.currentThread().getName());
                try {
                    Thread.sleep(8 * 1000L);
                    return "小单 - " + System.currentTimeMillis();
                } catch (InterruptedException e) {
                    return JSON.toJSONString(CcdcODataServerError.builder().code("113").msg("timeout").tip("timeout tip").build());
                }
            }
        };
    }

    @GetMapping("/max10secs")
    public String max10secs() throws InterruptedException, ExecutionException {
        System.out.println("max10secs" + Thread.currentThread().getName());
        Future<String> futureResponse = service.call();
        try {
            //gives 10 seconds to finish the methods execution
            return futureResponse.get(1, TimeUnit.SECONDS);
        } catch (TimeoutException te) {
            //in case it takes longer we cancel the request and check if the method is not done
            if (futureResponse.cancel(true) || !futureResponse.isDone())
                //throw new TestTimeoutException();
                return JSON.toJSONString(CcdcODataServerError.builder().code("112").msg("timeout").tip("timeout tip").build());
            else {
                return futureResponse.get();
            }
        }
    }

    @RequestMapping("/process")
    public void process(HttpServletRequest req, HttpServletResponse resp) throws IOException, InterruptedException {
        System.out.println("Main Async Start:" + Thread.currentThread().getName());
        req.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);
        AsyncContext asyncContext = req.startAsync();
        asyncContext.addListener(new ODataAsynListener());
        asyncContext.setTimeout(5 * 1000L);

        // max 10 seconds
        int secs = 4 * 1000;

        ThreadPoolExecutor executor = (ThreadPoolExecutor) req
                .getServletContext().getAttribute("executor");

        executor.execute(new AsyncRequestProcessor(asyncContext, secs));

        Thread.sleep(2000);

        System.out.println("Main Async End:" + Thread.currentThread().getName());

//        String data = "中国";
        /*OutputStream outputStream = resp.getOutputStream();//获取OutputStream输出流
        resp.setHeader("content-type", "text/html;charset=UTF-8");
        byte[] dataByteArr = data.getBytes("UTF-8");//将字符转换成字节数组，指定以UTF-8编码进行转换
        outputStream.write(dataByteArr);*/

       /* asyncContext.getResponse().getWriter().write(data);

        asyncContext.complete();*/

    }


    @RequestMapping("/proc")
    public void proc(HttpServletRequest req) throws Exception {
        log.info("Main {} is Start!", Thread.currentThread().getName());
        //req.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);
        AsyncContext asyncContext = req.startAsync();

        HttpServletResponse response = (HttpServletResponse) asyncContext.getResponse();
        Future<String> futureResult = task.run();

        try {
            String result = futureResult.get(5, TimeUnit.SECONDS);
            System.out.println(result);
            response.getWriter().write(result);
        } catch (InterruptedException e) {
            CcdcODataServerError serverError = CcdcODataServerError.builder().code("111").msg(e.getMessage()).tip("Request InterruptedException").build();
            response.getWriter().write(JSON.toJSONString(serverError));
            futureResult.cancel(true);
        } catch (ExecutionException e) {
            CcdcODataServerError serverError = CcdcODataServerError.builder().code("112").msg(e.getMessage()).tip("Request ExecutionException").build();
            response.getWriter().write(JSON.toJSONString(serverError));
            futureResult.cancel(true);
        } catch (TimeoutException e) {
            CcdcODataServerError serverError = CcdcODataServerError.builder().code("113").msg(e.getMessage()).tip("Request TimeoutException").build();
            response.getWriter().write(JSON.toJSONString(serverError));
            futureResult.cancel(true);
        } catch (IOException e) {
            CcdcODataServerError serverError = CcdcODataServerError.builder().code("114").msg(e.getMessage()).tip("Request IOException").build();
            response.getWriter().write(JSON.toJSONString(serverError));
            futureResult.cancel(true);
        }
        log.info("Main {} is Down!", Thread.currentThread().getName());
        asyncContext.complete();
        return;

    }

    @Async("taskExecutor")
    public void asyncProc(AsyncContext asyncContext) throws IOException, InterruptedException {

        Thread.sleep(10 * 1000);
        System.out.println("async proc:" + Thread.currentThread().getName());

        String data = "中国";
        /*OutputStream outputStream = resp.getOutputStream();//获取OutputStream输出流
        resp.setHeader("content-type", "text/html;charset=UTF-8");
        byte[] dataByteArr = data.getBytes("UTF-8");//将字符转换成字节数组，指定以UTF-8编码进行转换
        outputStream.write(dataByteArr);*/

        asyncContext.getResponse().getWriter().write(data);

        asyncContext.complete();
    }


    private static void closeStream(Channel closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
                // ignore
            }
        }
    }
}
